
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#include "soc.h"
#include "dw_i2c.h"
#include "dbg_cli.h"
#include "dbg_qspi.h"
#include "upaket.h"
#include "umsg.h"



/*
    debug bridge spi 是个 6 pin 接口,  cs, clk, dat[3:0];
    在 milkv-duo 开发板上, 选择 SPI-NOR-NAND 对应的 6 pin 接口;
   
    PAD     XGPIOA    SPI-NOR      milkv-duo
    17      26        HOLD#        GP21
    18      22        SCK          GP18
    19      25        MOSI         GP19
    20      27        WP#          GP20
    21      23        MISO         GP16
    22      24        CS#          GP17

    
    对于芯片的 PAD MUX 和 PAD control 的寄存器是按照 PAD 位置来定义.
*/

void qspi_pad_config( void )
{

#if 0

	/* GPIO */
	write_reg( PAD_MUX_17, 3 );
	write_reg( PAD_MUX_18, 3 );
	write_reg( PAD_MUX_19, 3 );
	write_reg( PAD_MUX_20, 3 );
	write_reg( PAD_MUX_21, 3 );
	write_reg( PAD_MUX_22, 3 );
#else

	/* SPI-NOR, */
	write_reg( PAD_MUX_17, 1 );
	write_reg( PAD_MUX_18, 1 );
	write_reg( PAD_MUX_19, 1 );
	write_reg( PAD_MUX_20, 1 );
	write_reg( PAD_MUX_21, 1 );
	write_reg( PAD_MUX_22, 1 );

	/* IIC-0 */
	write_reg( PAD_MUX_23, 4 );
	write_reg( PAD_MUX_24, 4 );

#endif

	
	// [11] 输出电平转换速率限制. 0=无效(较快) ; 1=有效(较慢)
	// [8] 输入施密特触发强度?
	// [7:5] 输出驱动能力.
    // [3] 下拉电阻, 0=无效; 1=有效
    // [2] 上拉电阻, 0=无效; 1=有效

	// PAD_CTL_17
	// PAD_CTL_18
	// PAD_CTL_19
	// PAD_CTL_20
	// PAD_CTL_21
	// PAD_CTL_22
}




int bl2_dbg_info( void * pctx, int argc, const char * argv[] )
{
	uint64_t temp;

	temp = csr_read( mapbaddr );

	printf( "mapbaddr = %x, %x\n",  (uint32_t)(temp >> 32),  (uint32_t)temp );
	return 0;
}



/*
关闭 data cache
*/
int bl2_dbg_cache( void * pctx, int argc, const char * argv[] )
{
	uint64_t temp;
	
	/**/
	__DCACHE_CIALL();
	__DSB();

	temp = __get_MHCR();
	__set_MHCR( temp & 0xFFD );
	
	printf( "mhcr org = %x\n", (uint32_t)temp );
	return 0;
}





extern int bl2_dbg_usb_init( void * pctx, int argc, const char * argv[] );



int log_init( int tsiz );
int log_flush( void );


int bl2_dbg_logcat( void * pctx, int argc, const char * argv[] )
{
	log_flush();
	return 0;
}


int bl2_dbg_rtscore( void * pctx, int argc, const char * argv[] )
{
	uint32_t temp;
	uint32_t tsiz;

	// check : 0x0E000040, 0x0E000044, 0x0E00004C .
	temp = read_reg( 0x0E00004C );
	if ( temp != 0x87654321 )  {
		return 123;
	}

	// memcpy
	temp = read_reg( 0x0E000040 );
	tsiz = read_reg( 0x0E000044 );
	memcpy( (void *)(intptr_t)0x3BC00000, (void *)(intptr_t)temp, (size_t)tsiz );

	// SEC_SUBSYS_BASE
	write_reg( 0x020B0004, 0x2000 );
	write_reg( 0x020B0020, 0x3BC00000 );
	write_reg( 0x020B0024, 0 );
	
	/**/
	__DCACHE_CIALL();
	__DSB();

	// 
	temp = read_reg( 0x03003024 );
	temp = temp | 0x40;
	write_reg( 0x03003024, temp );
	return 0;
}



int test_ecall( uint32_t esno, intptr_t arg0, intptr_t arg1, intptr_t arg2 )
{
    register uintptr_t a7 asm("a7") = (uintptr_t)esno;
    register intptr_t a0 asm("a0") = arg0;
    register intptr_t a1 asm("a1") = arg1;
    register intptr_t a2 asm("a2") = arg2;
	    
    asm volatile("ecall"
                : "+r"(a0)
                : "r"(a1), "r"(a2), "r"(a7)
                : "memory");
	return a0;
}


void  umsg_send_to_host( umsg_t * pmsg )
{
	// pack rqc
	pmsg->data[0] = (uint8_t)pmsg->rqc;
	pmsg->data[1] = (uint8_t)( pmsg->rqc >> 8 );

	pmsg->data[2] = (uint8_t)pmsg->seq;
	pmsg->data[3] = (uint8_t)( pmsg->seq >> 8 );

	test_ecall( 123, (intptr_t)(pmsg->data), pmsg->offs, 0 );
}


void * umsg_alloc_for_user( void )
{
	int iret;
	
	iret = test_ecall( 134, 0, 0, 0 );
	return (void *)(intptr_t)iret;
}


/*
uint16_t  reqc;	// 
*/


#define  RQC_SPI_READ		0x0011
#define  RQC_SPI_WRITE		0x0012

#define  RQC_DDR_READ		0x0202
#define  RQC_DDR_WRITE		0x0207

#define  RQC_ADI_READ		0x0101
#define  RQC_ADI_WRITE		0x0102

#define  RQC_CVB_READ		0x0702
#define  RQC_CVB_WRITE		0x0707

#define  RQC_IIC_CONFIG		0xFF08			// SI5324, PLL-CONFIG
#define  RQC_SYS_RESET		0xFF10



/*
输入的 msg 谁来释放?

如果返回 0 , 那么此函数已经回馈了 msg 给 host .

如果其他错误码? 需要总体框架通过错误机制来记录或上报.
*/
int proc_spi_read( umsg_t * pmsg )
{
	int iret;
	uint32_t addr;
	uint32_t cntw;
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;

	iret = umsg_remains( pmsg );
	if ( iret < 8 )  {
		return 1234;
	}

	addr = umsg_get_u32( pmsg );
	cntw = umsg_get_u32( pmsg );

	/* range check */
	if ( addr >= 0x4000000 ) {
		return 1235;
	}

	if ( cntw > 126 )  {
		return 1237;
	}

	// pack data to umsg.
	umsg_reset_ofs( pmsg );
	umsg_add_u32( pmsg, 0 );

	iret = dbg_qspi_read( psnor, addr, (int)cntw, (uint32_t *)umsg_curr( pmsg ) );
	if ( iret != 0 )  {
		return 1000 + iret;
	}

	// expand packet length..
	umsg_skip( pmsg, (int)(cntw * 4) );
	umsg_send_to_host( pmsg );
	return 0;
}



int proc_spi_write( umsg_t * pmsg )
{
	int iret;
	int cntw;
	uint32_t addr;
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;

	// 根据 umsg 剩余长度, 来计算要写到 spi 的数据个数.
	iret = umsg_remains( pmsg );
	if ( iret < 8 )  {
		return 2345;
	}

	addr = umsg_get_u32( pmsg );
	cntw = (uint32_t)( iret - 4 ) / sizeof(uint32_t);
	
	// 因为 header 和 addr 都是 4 字节, 所以数据部分是 4 字节对齐.
	iret = dbg_qspi_write( psnor, addr, cntw, (uint32_t *)umsg_curr( pmsg ) );
	if ( iret != 0 )  {
		return 1000 + iret;
	}

	// pack data to umsg.
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}


#if  0

/*
2 字节的 RQC 之后.
是个 reg addr 数组,  数组的成员都是 byte 大小.

0x300 : 
  [31] : 0 表示操作完成.
  [15] : 0-write, 1-read.
[14:8] : ad9685, reg addr.
 [7:0] : ad9685, reg data.
*/
int proc_adi_read( umsg_t * pmsg )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	int cntw;
	uint8_t tary[20];
	uint32_t temp;
	uint64_t told;
	uint64_t tnew;


	//
	cntw = umsg_remains( pmsg );
	for ( int i=0; i<cntw; i++ ) {
		tary[i]	= umsg_get_u8( pmsg );
		printf( "adi read idx : %x\n", tary[i] );
	}

	// 
	umsg_reset_ofs( pmsg );

	for ( int i=0; i<cntw; i++ ) {

		temp = 0x80 | tary[i];
		temp = temp << 8;
		test_write( psnor, 0x300, 1, &temp );

		told = __get_MTIME();

		while ( true ) {
			test_read( psnor, 0x300, 1, &temp );

			if ( (temp & 0x80000000) == 0 )  {
				break;
			}

			// check timeout
			tnew = __get_MTIME();
			if ( (tnew - told) >= 2500000 )  {

				umsg_reset_ofs( pmsg );
				umsg_add_i32( pmsg, 0x45678 );
				umsg_send_to_host( pmsg );
				return 0;
			}
		}

		//
		printf( "300: %x\n", temp );
		umsg_add_u8( pmsg, (uint8_t)(temp & 0xff) );
	}
	
	umsg_send_to_host( pmsg );
	return 0;
}


int proc_adi_write( umsg_t * pmsg )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	int cntw;
	uint16_t tary[20];
	uint32_t temp;

	//
	cntw = umsg_remains( pmsg );
	for ( int i=0; i<cntw; i+=2 ) {
		tary[i]	= umsg_get_u8( pmsg );
		tary[i]	= (tary[i] << 8) | umsg_get_u8( pmsg );
		printf( "idx : %x\n", tary[i] );
	}

	// 
	cntw = cntw / 2;
	for ( int i=0; i<cntw; i++ ) {

		temp = tary[i];
		test_write( psnor, 0x300, 1, &temp );

		while ( true ) {
			test_read( psnor, 0x300, 1, &temp );

			if ( (temp & 0x80000000) == 0 )  {
				break;
			}
		}

		//
		printf( "300: %x\n", temp );
	}
	
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}

#endif



/// @brief SI5324写寄存器
/// @param address 外设地址
/// @param RegAde  写的寄存器地址
/// @param value 写的值
int SI5324_WriteReg( uint32_t address, uint8_t RegAde, uint8_t value)
{
	dw_iic_regs_t * piic = (dw_iic_regs_t *)0x04000000;
    uint32_t temp;
	
    /**/
    dw_iic_set_target_address( piic, address );
    dw_iic_clear_all_irq( piic );
    dw_iic_enable( piic );
    
    /* write */
    piic->IC_DATA_CMD = RegAde;
	piic->IC_DATA_CMD = (0x2<<8)|value;
    

    /* wait */
    while ( 1 ) {
        if ( piic->IC_RAW_INTR_STAT & DW_IIC_RAW_TX_ABRT ) {
            break;
        }

        if ( piic->IC_TXFLR == 0 ) {
            break;
        }
    }
    
    if ( piic->IC_RAW_INTR_STAT & DW_IIC_RAW_TX_ABRT ) {
        temp = piic->IC_TX_ABRT_SOURCE;
        printf( "tx fail, %08x\n", temp );

        /**/
        dw_iic_disable( piic );
        return (int)__LINE__;
    }

    /* finish, deinit */
    dw_iic_disable( piic );
    return 0;
}


int proc_iic_config( umsg_t * pmsg )
{
	int iret;
	dw_iic_regs_t * piic = (dw_iic_regs_t *)0x04000000;
	int cntw;
	uint8_t addr[64];
	uint8_t vals[64];

	//
	cntw = umsg_remains( pmsg );
	cntw = cntw / 2;

	for ( int i=0; i<cntw; i++ ) {
		addr[i]	= umsg_get_u8( pmsg );
		vals[i]	= umsg_get_u8( pmsg );
		printf( "idx : %x\n", addr[i] );
	}


    /**/
    dw_iic_init( piic, 300000 );
    dw_iic_set_master_mode( piic );
    dw_iic_set_transfer_speed_fast( piic );

	//
	for ( int i=0; i<cntw; i++ ) {
		iret = SI5324_WriteReg( 0x68, addr[i], vals[i] );
		if ( iret != 0 )  {
			return (int)__LINE__;
		}
	}

	/* 0 表示成功. */
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}




/* read loop 全局信息. */
typedef struct _tag_rlp_context  {

	uint32_t addr;
	uint32_t cntw;
	uint32_t offs;
	int flag;

	// 
	umsg_t tmsg;

} rlp_context_t;




int rdloop_new_work( rlp_context_t * pctx, uint32_t addr, uint32_t cntw )
{
	pctx->addr = addr;
	pctx->cntw = cntw;
	pctx->offs = 0;
	pctx->flag = 123;
	return 0;
}


/*
事务处于进行中.
*/
int rdloop_is_pending( rlp_context_t * pctx )
{
	return (int)( pctx->flag != 0 );
}


/*
完成一个步骤.
*/
int rdloop_do_step( rlp_context_t * pctx )
{
	int iret;
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	const uint32_t sampb = 0x150000;
	umsg_t * pmsg;
	int rcnt;
	uint32_t winbp;
	uint32_t taddr;


	if ( pctx->flag == 0 )  {
		// nothing to do.
		return 1;
	}

	// alloc packet
	pmsg = &( pctx->tmsg );
	pmsg->data = (uint8_t *)umsg_alloc_for_user();
	if ( pmsg->data == NULL )  {
		printf( "error : mem read loop, alloc pmsg NULL\n" );
		return 333;
	}

	// init data
	pmsg->rqc = 0xAA01;
	pmsg->seq = 0;
	pmsg->mlen = 512;
	umsg_reset_ofs( pmsg );
	umsg_add_u32( pmsg, pctx->offs );


	if ( pctx->offs >= pctx->cntw )  {

		// send tail packet...
		umsg_send_to_host( pmsg );
		pctx->flag = 0;
		return 0;
	}
	
	// 
	rcnt = pctx->cntw - pctx->offs;
	if ( rcnt > 126 )  {
		rcnt = 126;
	}

	// write ddr windows pointer
	taddr = pctx->addr + (pctx->offs << 2);
	winbp = taddr & 0xFFFFF000;
	dbg_qspi_write( psnor, (sampb + 0x0), 1, &winbp );
	// printf( "step, addr : %x\n", taddr );
	// test_sleep( 10000 );

	// todo : 如果出现错误?? stop / retry???
	taddr = sampb + 0x1000 + (taddr - winbp);
	iret = dbg_qspi_read( psnor, taddr, rcnt, (uint32_t *)umsg_curr(pmsg) );
	if ( iret != 0 )  {
		
		// 结束 rdloop, 发送短 packet 表示 EOF..
		umsg_send_to_host( pmsg );
		pctx->flag = 0;

		printf( "step, qspi read err : %d\n", iret );
		return 334;
	}

	// expand packet length..
	umsg_skip( pmsg, (int)(rcnt * 4) );
	umsg_send_to_host( pmsg );

	// update context
	pctx->offs += (uint32_t)rcnt;
	return 0;
}





/*
input : 
	uint16  rqc;	// 
	uint16  seq;

	uint32  addr;	// 地址需要 4 字节对齐.
	uint32  size;	// 表示要读出来的 word 数量.

output [0]:
	uint16  rqc;
	uint16  seq;
	
	uint32  errcode;
	
	第一个返回给 pc 的 packet,  仅仅是为了完成 rpc 调用流程.
	errcode = 0 , 表示地址检查通过.

output [n]:

	uint16  rqc;	// special : 0xAA01
	uint16  seq;	// 是否有特殊意义??

	uint32  offs;
	uint32  array[126];		
	
	// 可以认为是一种特殊的 data pakcet,  开始的 offs = 0,  随后每个 packet 中的 offs 递增, 实际是表示已经传输的 word 个数.
	// 每次最多 126 个 word , 因为 usb 最大 packet 是 512 字节.
	
	// 在 cv1800b 上,  一次 input 请求, 导致持续的循环上送.
	// 如果第一个上送的 offs 不是 0 ,  表示错误码.
	// 如果后续 offs 不连续, 也可以用来表示错误码.
*/

static rlp_context_t rlpctx;

int proc_ddr_read( umsg_t * pmsg )
{
	int iret;
	uint32_t addr;
	uint32_t tsiz;

	iret = umsg_remains( pmsg );
	if ( iret < 8 )  {
		return 1231;
	}

	// tsiz 是字节单位, 需要 4 字节对齐.
	addr = umsg_get_u32( pmsg );
	tsiz = umsg_get_u32( pmsg );

	if ( (addr & 0x3) != 0 )  {
		// check align
		return 1234;
	}

	if ( ((tsiz & 0x3) != 0)  || (tsiz == 0) )  {
		return 1235;
	} 

	if ( rdloop_is_pending( &rlpctx ) ) {
		// 已经有正在运行的 read loop ???
		return 1237;
	}

	// save data for loop read.
	rdloop_new_work( &rlpctx, addr, (tsiz >> 2) );

	/*  0 表示 succ. */
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}


/*
input :
	uint16  rqc;
	uint16  seq;
	uint32  addr;			// 地址需要 4 字节对齐.
	uint32  array[126];		// 每次最多 126 个 word , 因为 usb 最大 packet 是 512 字节.

output :
	uint16  rqc;
	uint16  seq;
	uint32  errcode;

ddr 的写操作,  每次最多 126 个 word,  每次都需要 rpc 交互.
相对于 ddr 读操作, 是个低速动作.

*/


int proc_ddr_write( umsg_t * pmsg )
{
	int iret;
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	const uint32_t sampb = 0x150000;
	int cntw;
	uint32_t addr;
	uint32_t winbp;


	// 消息中至少需要包含 addr 以及一个 data;
	cntw = umsg_remains( pmsg );
	if ( cntw < 8 )  {
		return 400;
	}

	addr = umsg_get_u32( pmsg );
	cntw = (cntw / 4) - 1;

	// write ddr windows pointer
	winbp = addr & 0xFFFFF000;
	iret = dbg_qspi_write( psnor, (sampb + 0x0), 1, &winbp );
	if ( iret != 0 )  {
		return 1230;
	}

	// 因为 header 和 addr 都是 4 字节长度, 所以能保证数据部分是对齐在 4 字节.
	addr = sampb + 0x1000 + (addr - winbp);
	iret = dbg_qspi_write( psnor, addr, cntw, (uint32_t *)umsg_curr( pmsg ) );
	if ( iret != 0 )  {
		return 1231;
	}
	
	// return success.
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}


int proc_cvb_read( umsg_t * pmsg )
{
	int iret;
	uintptr_t radr;
	uint32_t cntw;
	uint32_t * pdat;

	iret = umsg_remains( pmsg );
	if ( iret < 8 )  {
		return 1234;
	}

	radr = umsg_get_u32( pmsg );
	cntw = umsg_get_u32( pmsg );

	if ( cntw > 126 )  {
		return 1237;
	}

	// pack data to umsg.
	umsg_reset_ofs( pmsg );
	umsg_add_u32( pmsg, 0 );

	//
	pdat = (uint32_t *)umsg_curr( pmsg );

	for ( uint32_t i=0; i<cntw; i++ )  {
		pdat[i] = read_reg( radr );
		radr = radr + 4;
	}
	
	// expand packet length..
	umsg_skip( pmsg, (int)(cntw * 4) );
	umsg_send_to_host( pmsg );
	return 0;
}


int proc_cvb_write( umsg_t * pmsg )
{
	int iret;
	int cntw;
	uintptr_t radr;
	uint32_t * pdat;
	
	// 根据 umsg 剩余长度, 来计算要写到 spi 的数据个数.
	iret = umsg_remains( pmsg );
	if ( iret < 8 )  {
		return 2345;
	}

	radr = umsg_get_u32( pmsg );
	cntw = (uint32_t)( iret - 4 ) / sizeof(uint32_t);
	
	// 因为 header 和 addr 都是 4 字节, 所以数据部分是 4 字节对齐.
	pdat = (uint32_t *)umsg_curr( pmsg );
	for ( int i=0; i<cntw; i++ )  {
		write_reg( radr, pdat[i] );
		radr = radr + 4;
	}

	// pack data to umsg.
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}




#if  1

int main( void )
{
	int iret;
	int tlen;
	void * ptr;
	umsg_t tmsg;

	// 
	qspi_pad_config();
	log_init( 16000 );

	bl2_dbg_nor( NULL, 0, NULL );

	/* packet memory pool ...*/
	iret = upk_init();
	printf( "upk pool init = %d\n", iret );

	// global MIE.
	__enable_irq();
	bl2_dbg_usb_init( NULL, 0, NULL );
	test_sleep( 100000 );

	// rdloop.
	rlpctx.flag = 0;
	rlpctx.offs = 0;
	rlpctx.addr = 0;
	rlpctx.cntw = 0;
	

	/**/
	while ( true )  {
	
		// __disable_irq();
		iret = upk_recv_from_dev( &ptr, &tlen );
		// __enable_irq();

		if ( iret != 0 )  {
			
			//
			if ( rdloop_is_pending( &rlpctx) )  {
				
				rdloop_do_step( &rlpctx );

			} else {

				__WFI();
			}

			continue;
		}

		if ( tlen < 2 )  {
			/* dump */
			debug_dump_hex( ptr, tlen );
			continue;
		}

		/* special, system reset */
		tmsg.rqc = *(uint16_t *)ptr;
		tmsg.seq = *((uint16_t *)ptr + 1);
		if ( tmsg.rqc == RQC_SYS_RESET )  {
			break;
		}

		tmsg.data = (uint8_t *)ptr;
		tmsg.offs = 4;
		tmsg.mlen = tlen;

		// printf( "bff %x\n", tmsg.rqc );

		switch ( tmsg.rqc )  {

		case RQC_SPI_READ:
			iret = proc_spi_read( &tmsg );
			break;

		case RQC_SPI_WRITE:
			iret = proc_spi_write( &tmsg );
			break;
		
		case RQC_DDR_WRITE:
			iret = proc_ddr_write( &tmsg );
			break;

		case RQC_DDR_READ:
			iret = proc_ddr_read( &tmsg );
			break;

		case RQC_CVB_READ:
			iret = proc_cvb_read( &tmsg );
			break;

		case RQC_CVB_WRITE:
			iret = proc_cvb_write( &tmsg );
			break;

		default:
			iret = 12345678;
			break;
		}

		if ( iret != 0 )  {

			umsg_reset_ofs( &tmsg );
			umsg_add_i32( &tmsg, iret );
			umsg_send_to_host( &tmsg );

			printf( "err : %x , %d\n", tmsg.rqc, iret );
		}
	}

	// 
	return 0;
}


#else


extern int bl2_dbg_uid( void * pctx, int argc, const char * argv[] );
extern int bl2_dbg_dread( void * pctx, int argc, const char * argv[] );


int main( void )
{
	int iret;
	char spad[128];

	printf( "hello...\n" );
	qspi_pad_config();
	// 
	log_init( 16000 );

	//
	debug_cli_init();
	debug_add_cmd( "nor", bl2_dbg_nor, NULL );
	debug_add_cmd( "dread", bl2_dbg_dread, NULL );

	debug_add_cmd( "logcat", bl2_dbg_logcat, NULL );
	debug_add_cmd( "cache", bl2_dbg_cache, NULL );
	debug_add_cmd( "rtscore", bl2_dbg_rtscore, NULL );
	debug_add_cmd( "uid", bl2_dbg_uid, NULL );
	
	/* packet memory pool ...*/
	iret = upk_init();
	printf( "upk pool init = %d\n", iret );

	// global MIE.
	__enable_irq();

	/**/
	while ( true )  {

		/* read line */
		iret = cons_readline( ">> ", 120, spad );
		if ( iret != 0 ) {
			continue;
		}
			
		if ( 0 == strcmp( spad, "quit" ) )  {
			break;
		}

		/* proc */
		debug_proc_line( spad );
	}

	/**/
	return 0;
}

#endif
